#ifndef REL_OP_H
#define REL_OP_H

#include "pthread.h"
#include "Pipe.h"
#include "DBFile.h"
#include "Record.h"
#include "Function.h"

class RelationalOp {
public:
    // blocks the caller until the particular relational operator
    // has run to completion
    virtual void WaitUntilDone () = 0;

    // tell us how much internal memory the operation can use
    virtual void Use_n_Pages (int n) = 0;
};

// maybe a bad style.. I want to it to be usable only for class SelectFile
// but I do not know whether I could define it inside SelectFile or not
class SelectFileInfo {
public:
    DBFile* inFile;
    Pipe* outPipe;
    CNF* selOp;
    Record* literal;
    int numPages;
};

class SelectFile : public RelationalOp {

private:
    pthread_t thread;
    //Record *buffer;
    SelectFileInfo* sfInfo;
    int numPages;

public:
    void Run (DBFile &inFile, Pipe &outPipe, CNF &selOp, Record &literal);
    void WaitUntilDone ();
    void Use_n_Pages (int n);

};

class SelectPipe : public RelationalOp {
private:
    //int numPages;

public:
    void Run (Pipe &inPipe, Pipe &outPipe, CNF &selOp, Record &literal);
    void WaitUntilDone () { }
    void Use_n_Pages (int n) { }
};

class ProjectInfo {
public:
    Pipe* inPipe;
    Pipe* outPipe;
    int* keepMe;
    int numAttsInput;
    int numAttsOutput;
    int numPages;
};

class Project : public RelationalOp {
private:
    pthread_t thread;
    int numPages;

public:
    void Run (Pipe &inPipe, Pipe &outPipe, int *keepMe, int numAttsInput, int numAttsOutput);
    void WaitUntilDone ();
    void Use_n_Pages (int n);
};

class JoinInfo {
public:
    Pipe* inPipeL;
    Pipe* inPipeR;
    Pipe* outPipe;
    CNF* selOp;
    Record* literal;
    int numPages;
};

class Join : public RelationalOp {
private:
    pthread_t thread;
    int numPages;
public:
    void Run (Pipe &inPipeL, Pipe &inPipeR, Pipe &outPipe, CNF &selOp, Record &literal);
    void WaitUntilDone ();
    void Use_n_Pages (int n);
};

class DupRemovalInfo {
public:
    Pipe* inPipe;
    Pipe* outPipe;
    Schema* mySchema;
    int numPages;
};

//struct HashEqStr {
//    bool operator () (const char* r1, const char* r2) const
//    {
//        return strcmp(r1, r2) == 0;
//    }
//};

class HashEqStr {
private:
    OrderMaker sortorder;

public:
    HashEqStr (OrderMaker sortorder)
    {
        sortorder.Copy(this->sortorder);
    }

    bool operator () (Record* left, Record* right)
    {
        ComparisonEngine compEng;
        return compEng.Compare(left, right, &sortorder) < 0;
    }
};

class DuplicateRemoval : public RelationalOp {
private:
    pthread_t thread;
    int numPages;

public:
    void Run (Pipe &inPipe, Pipe &outPipe, Schema &mySchema);
    void WaitUntilDone ();
    void Use_n_Pages (int n);
};

class SumInfo {
public:
    Pipe* inPipe;
    Pipe* outPipe;
    Function computeMe;
    int numPages;
};

class Sum : public RelationalOp {
private:
    pthread_t thread;
    int numPages;

public:
    void Run (Pipe &inPipe, Pipe &outPipe, Function &computeMe);
    void WaitUntilDone ();
    void Use_n_Pages (int n);
};

class GroupHashEqStr {
private:
    OrderMaker sortorder;

public:
    GroupHashEqStr (OrderMaker sortorder)
    {
        sortorder.Copy(this->sortorder);
    }

    bool operator () (vector<Record*>* left, vector<Record*>* right)
    {
        ComparisonEngine compEng;
        return compEng.Compare(left->at(0), right->at(0), &sortorder) < 0;
    }
};

class GroupByInfo {
public:
    Pipe* inPipe;
    Pipe* outPipe;
    OrderMaker* groupAtts;
    Function computeMe;
    int numPages;
};

class GroupBy : public RelationalOp {
private:
    pthread_t thread;
    int numPages;

public:
    void Run (Pipe &inPipe, Pipe &outPipe, OrderMaker &groupAtts, Function &computeMe);
    void WaitUntilDone ();
    void Use_n_Pages (int n);
};

class WriteOutInfo {
public:
    Pipe* inPipe;
    FILE* outFile;
    Schema* mySchema;
    int numPages;
};

class WriteOut : public RelationalOp {
private:
    pthread_t thread;
    int numPages;

public:
    void Run (Pipe &inPipe, FILE *outFile, Schema &mySchema);
    void WaitUntilDone ();
    void Use_n_Pages (int n);
};
#endif
